﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;

namespace CPPEI.Coolzon.UI
{
    [System.ComponentModel.DisplayName("场景")]
    public partial class ScenePart : Part, IPartContainer
    {
        static ScenePart()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ScenePart), new FrameworkPropertyMetadata(typeof(ScenePart)));
        }

        /// <summary>
        /// 通过调用scenePart.RaiseScriptEvent("OnReceiveNetEvent", data);来触发
        /// </summary>
        public static XEvent XEventOnReceiveNetEvent = XEventManager.Register(typeof(ScenePart),
            "OnReceiveNetEvent",
            new XEventArgument("sender", typeof(Script.PartScriptObject)),
            new XEventArgument("data", typeof(Script.SceneNetScriptObject)));

        public static XEvent XEventOnActiveEvent = XEventManager.Register(typeof(ScenePart),
            "OnActive",
            new XEventArgument("sender", typeof(Script.PartScriptObject)));

        private List<Action<string, string>> _netEventCallbackList = new List<Action<string, string>>();

        public void AddNetEventCallback(Action<string, string> callback)
        {
            _netEventCallbackList.Add(callback);
        }

        private List<Script.TimerInst> _timerInstList = new List<Script.TimerInst>();

        public void StartTimer(double interval, string func)
        {
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(interval);
            timer.Tick += timer_Tick;
            timer.Tag = func;
            timer.Start();

            _timerInstList.Add(new Script.TimerInst()
            {
                Id = _timerInstList.Count + 1,
                Timer = timer
            });
            Common.Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("场景:{0}启动定时器", this.Name));
        }

        void timer_Tick(object sender, EventArgs e)
        {
            string func =(string) (sender as DispatcherTimer).Tag;
            this.PartContext.ScriptEngine.Run(func);
        }

        private List<AreaPart> _subAreas;

        /// <summary>
        /// 场景中包含的子组件集合
        /// </summary>
        PartCollection _partCollection;
        private Canvas _canvas;

        public Layout Layout { get; set; }

        public Metadata.Scene SceneMatadata
        {
            get
            {
                return (Metadata.Scene)Metadata;
            }
            set
            {
                Metadata = value;
            }
        }

        public ChildrenPosInfo ChildrenPosInfo { get; set; }

        public ScenePart()
        {
            _subAreas = new List<AreaPart>();
            ChildrenPosInfo = new ChildrenPosInfo();
            _partCollection = new PartCollection(this);
            XBackground = new BrushEx(new SolidColorBrush(Colors.White));

            _canvas = new Canvas();
            this.Content = _canvas;
        }

        public string Caption { get; set; }

        /// <summary>
        /// 滚动动画对象
        /// </summary>
        Storyboard _loopAnimation;
        DoubleAnimation _loopDoubleAnimation;
        /// <summary>
        /// 动画结束时要到达的目标值，用于动画还没结束又收到新的滚动事件
        /// </summary>
        double _loopAnimationDestValue;

        /// <summary>
        /// 设置元数据
        /// </summary>
        /// <param name="sceneMetadata"></param>
        public void SetMetadata(Metadata.Scene sceneMetadata)
        {
            this.SceneMatadata = sceneMetadata;
        }

        /// <summary>
        /// 重置区域的位置
        /// </summary>
        public void ResetRootAreaPos()
        {
            if (SceneMatadata == null)
            {
                Coolzon.Common.Logger.WarningToTag("Coolzon.UI", "场景:{0}ResetRootAreaPos，SceneMetadata为null", this.Name);
                return;
            }
            if (SceneMatadata.Areas == null)
            {
                Coolzon.Common.Logger.WarningToTag("Coolzon.UI", "场景:{0}ResetRootAreaPos，SceneMetadata.Areas为null", this.Name);
                return;
            }
            if (SceneMatadata.IsAllowSwapArea)
            {
                double leftOffset = 0;
                for (int index = 0; index < SceneMatadata.Areas.Count; index++)
                {
                    Coolzon.Metadata.Area areaMetadata = SceneMatadata.Areas[index];
                    UI.AreaPart area = this.GetChildPart(areaMetadata.Name, false) as UI.AreaPart;
                    if (area != null)
                    {
                        area.XLeft = leftOffset;
                        leftOffset += area.XWidth;

                        ChildrenPosInfo.Set(areaMetadata.Name, area.XLeft);
                    }
                }
            }
        }

        public void ResetHorizontalLoop()
        {
            if (_loopAnimation != null)
            {
                _loopDoubleAnimation.From = 0;
                _loopDoubleAnimation.To = 0;
                _loopAnimation.Begin(this);
            }
            _destHLoopOffset = 0;

            HActualLoopOffset = 0;
            HVirtualLoopOffset = this.ActualWidth;
        }

        /// <summary>
        /// 小于0，往左
        /// 大于0，往右
        /// </summary>
        /// <param name="offset"></param>
        public void HorizontalLoop(double offset)
        {
            this.Dispatcher.Invoke(() =>
            {
                _destHLoopOffset += offset;
                if (CurrentHLoopOffset == 0 && _destHLoopOffset == 0)
                {
                    return;
                }

                if (_loopAnimation == null)
                {
                    _loopAnimation = new Storyboard();
                    _loopAnimation.Name = string.Format("LSB{0}", Guid.NewGuid().ToString("N"));

                    Common.Logger.DebugToTag("UI", "Loop Scene animation from:{0} to:{1}, to1:{2}", CurrentHLoopOffset, _destHLoopOffset, _destHLoopOffset);
                    _loopDoubleAnimation = new DoubleAnimation(CurrentHLoopOffset, _destHLoopOffset, new Duration(TimeSpan.FromMilliseconds(500)));
                    _loopDoubleAnimation.AccelerationRatio = 0.1d;
                    _loopDoubleAnimation.DecelerationRatio = 0.4d;
                    Storyboard.SetTarget(_loopDoubleAnimation, this);
                    Storyboard.SetTargetProperty(_loopDoubleAnimation, new PropertyPath(ScenePart.CurrentHLoopOffsetProperty));
                    _loopAnimation.Children.Add(_loopDoubleAnimation);
                }
                else
                {
                    _loopDoubleAnimation.From = CurrentHLoopOffset;
                    _loopDoubleAnimation.To = _destHLoopOffset;
                }

                _loopAnimation.Begin(this);
            });
        }

        void _loopAnimation_Completed(object sender, EventArgs e)
        {
            ClockGroup clock = sender as ClockGroup;
            Storyboard sourceStoryboard = clock.Timeline as Storyboard;
            if (sourceStoryboard.Name == _loopAnimation.Name)
            {
                Storyboard temp = _loopAnimation;
                _loopAnimation = null;
                temp.Stop();
                temp.Remove();

                CurrentHLoopOffset = _destHLoopOffset;
                _destHLoopOffset = _destHLoopOffset % this.ActualWidth;
                CurrentHLoopOffset = _destHLoopOffset;
                Common.Logger.DebugToTag("UI", "Loop Scene animation completed CurrentHLoopOffset:{0} _destHLoopOffset:{1}", CurrentHLoopOffset, _destHLoopOffset);
            }
        }

        private void UpdateLoopRenderState(double currentHLoopOffset)
        {
            double hActualLoopOffset = 0;
            double hVirtualLoopOffset = 0;
            hActualLoopOffset = currentHLoopOffset;
            hVirtualLoopOffset = this.ActualWidth + currentHLoopOffset;
            //Common.Logger.DebugToTag("UI", "ScenePart HLoop HActualLoopOffset:{0}, HVirtualLoopOffset:{1}, AcutalWidth:{2}",
            //    hActualLoopOffset,
            //    hVirtualLoopOffset,
            //    this.ActualWidth);
            if (hActualLoopOffset > this.ActualWidth)
            {
                hActualLoopOffset = (hActualLoopOffset % this.ActualWidth) - this.ActualWidth;
            }
            else if (hActualLoopOffset < -this.ActualWidth)
            {
                hActualLoopOffset = this.ActualWidth + (hActualLoopOffset % this.ActualWidth);
            }
            else if (hActualLoopOffset == this.ActualWidth)
            {
                hActualLoopOffset = 0;
            }

            if (hVirtualLoopOffset > this.ActualWidth)
            {
                if (hActualLoopOffset > 0)
                {
                    hVirtualLoopOffset = (hVirtualLoopOffset % this.ActualWidth) - this.ActualWidth;
                }
                else
                {
                    hVirtualLoopOffset = (hVirtualLoopOffset % this.ActualWidth);// -this.ActualWidth;
                }
            }
            else if (hVirtualLoopOffset < -this.ActualWidth)
            {
                if (hActualLoopOffset > 0)
                {
                    hVirtualLoopOffset = (hVirtualLoopOffset % this.ActualWidth);
                }
                else
                {
                    hVirtualLoopOffset = this.ActualWidth + (hVirtualLoopOffset % this.ActualWidth);
                }
            }

            //Common.Logger.DebugToTag("UI", "ScenePart HLoop adjusted HActualLoopOffset:{0}, HVirtualLoopOffset:{1}",
            //    hActualLoopOffset,
            //    hVirtualLoopOffset);
            HActualLoopOffset = hActualLoopOffset;
            HVirtualLoopOffset = hVirtualLoopOffset;
        }

        #region override Part

        protected override void OnInit(PartContext context)
        {
            for (int index = 0; index < this._partCollection.Count; index++)
            {
                this._partCollection[index].Init(context);
            }

            base.OnInit(context);
        }

        protected override void OnActive(PartContext context)
        {
            HorizontalLoop(0);

            for (int index = 0; index < _partCollection.Count; index++)
            {
                _partCollection[index].Active(context);
            }

            this.RaiseScriptEvent("OnActive", null);
            base.OnActive(context);
        }

        protected override void OnDeactive(PartContext context)
        {
            if (_loopAnimation != null)
            {
                _loopAnimation.Stop();
                _loopAnimation.Remove();
                _loopAnimation = null;
            }

            for (int index = 0; index < _partCollection.Count; index++)
            {
                _partCollection[index].Deactive();
            }

            base.OnDeactive(context);
        }

        protected override void OnDestory()
        {
            if (_timerInstList.Count != 0)
            {
                for (int index = 0; index < _timerInstList.Count; index++)
                {
                    _timerInstList[index].Timer.Stop();
                    Common.Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("场景:{0}关闭定时器", this.Name));
                }
            }

            if (_loopAnimation != null)
            {
                _loopAnimation.Stop();
                _loopAnimation.Remove();
                _loopAnimation = null;
            }

            for (int index = 0; index < _partCollection.Count; index++)
            {
                _partCollection[index].Destory();
            }

            // 移除引用
            for (int index = 0; index < _partCollection.Count; index++)
            {
                _canvas.Children.Remove(_partCollection[index]);

                _partCollection[index].ParentPart = null;
            }

            _partCollection.Clear();

            base.OnDestory();
        }

        protected override void OnFrozen()
        {
            for (int index = 0; index < this._partCollection.Count; index++)
            {
                this._partCollection[index].Frozen();
            }
            base.OnFrozen();
        }

        protected override void OnUnfreeze()
        {
            for (int index = 0; index < this._partCollection.Count; index++)
            {
                this._partCollection[index].Unfreeze();
            }
            base.OnUnfreeze();
        }

        protected override void OnReset()
        {
            ResetHorizontalLoop();
            ResetRootAreaPos();

            for (int index = 0; index < this._partCollection.Count; index++)
            {
                this._partCollection[index].Reset();
            }
        }

        public Point XGetContentPos()
        {
            return new Point(this.Padding.Left, this.Padding.Top);
        }

        #endregion

        /// <summary>
        /// 根据坐标获取根节点的区域对象
        /// </summary>
        /// <param name="ptInScene">场景中的坐标点</param>
        /// <returns></returns>
        public AreaPart GetRootArea(Point ptInScene)
        {
            for (int index = 0; index < this._subAreas.Count; index++)
            {
                AreaPart areaPart = this._subAreas[index];
                if (areaPart.XLeft <= ptInScene.X
                    && areaPart.XTop <= ptInScene.Y
                    && areaPart.XLeft + areaPart.XWidth >= ptInScene.X
                    && areaPart.XTop + areaPart.XHeight >= ptInScene.Y)
                {
                    return areaPart;
                }
            }
            return null;
        }

        /// <summary>
        /// 从场景中获取当前区域左侧的区域对象.
        /// <para>如果该区域已经位于最左侧则返回自己.</para>
        /// </summary>
        /// <param name="currentArea">当前区域对象</param>
        /// <returns>当前区域左侧的区域</returns>
        public AreaPart GetLeftRootArea(AreaPart currentArea)
        {
            // 当前区域左侧区域的left值应该小于当前区域的left值，且大于任何left小于当前区域的其他区域
            AreaPart leftArea = null;
            for (int index = 0; index < this._subAreas.Count; index++)
            {
                AreaPart areaPart = this._subAreas[index];
                if (areaPart.XLeft < currentArea.XLeft)
                {
                    if (leftArea == null)
                    {
                        leftArea = areaPart;
                    }
                    else if (areaPart.XLeft > leftArea.XLeft)
                    {
                        leftArea = areaPart;
                    }
                }
            }

            if (leftArea == null)
            {
                leftArea = currentArea;
            }

            return leftArea;
        }

        /// <summary>
        /// 从场景中获取当前区域右侧的区域对象.
        /// <para>如果该区域已经位于最右侧则返回自己.</para>
        /// </summary>
        /// <param name="currentArea">当前区域对象</param>
        /// <returns>当前区域右侧的区域</returns>
        public AreaPart GetRightRootArea(AreaPart currentArea)
        {
            // 当前区域左侧区域的left值应该大于当前区域的left值，且小于任何left大于当前区域的其他区域
            AreaPart rightArea = null;
            for (int index = 0; index < this._subAreas.Count; index++)
            {
                AreaPart areaPart = this._subAreas[index];
                if (areaPart.XLeft > currentArea.XLeft)
                {
                    if (rightArea == null)
                    {
                        rightArea = areaPart;
                    }
                    else if (areaPart.XLeft < rightArea.XLeft)
                    {
                        rightArea = areaPart;
                    }
                }
            }

            if (rightArea == null)
            {
                rightArea = currentArea;
            }

            return rightArea;
        }

        public override UI.Part GetPartAtPoint(Type type, Point pointInRoot, UIElement rootElement)
        {
            if (!XIsVisible)
            {
                return null;
            }
            UI.Part part = null;
            // Point absolutePoint = this.TranslatePoint(new Point(0, 0), rootElement);
            for (int index = 0; index < this._partCollection.Count; index++)
            {
                part = this._partCollection[index].GetPartAtPoint(type, pointInRoot, rootElement);
                if (part != null)
                {
                    return part;
                }
            }
            return base.GetPartAtPoint(type, pointInRoot, rootElement);
        }

        /// <summary>
        /// 测试是否x，y点是否命中了组件实例
        /// </summary>
        /// <param name="pointInScene">场景中的坐标点</param>
        /// <returns></returns>
        public override Data.XHitResult XHitTest(Point pointInScene)
        {
            if (!XIsVisible)
            {
                return new Data.XHitResult(false, null, default(Point));
            }

            Point pos = this.XGetAbsolutePos();
            Size size = this.XGetSize();

            if (pointInScene.X >= pos.X
                && pointInScene.Y >= pos.Y
                && pointInScene.X <= pos.X + size.Width
                && pointInScene.Y <= pos.Y + size.Height)
            {
                for (int index = this._partCollection.Count - 1; index >= 0; index--)
                {
                    Data.XHitResult hitResult = this._partCollection[index].XHitTest(pointInScene);
                    if (hitResult.IsSuccess)
                    {
                        return hitResult;
                    }
                }
                return new Data.XHitResult(true, this, new Point(pointInScene.X - pos.X, pointInScene.Y - pos.Y));
            }
            return new Data.XHitResult(false, null, default(Point));
        }

        /// <summary>
        /// 测试是否x，y点是否命中了组件实例
        /// </summary>
        /// <typeparam name="T">命中的组件必须属于这个类型</typeparam>
        /// <param name="pointInScene">场景中的坐标点</param>
        /// <returns></returns>
        public override Data.XHitResult XHitTest<T>(Point pointInScene)
        {
            if (!XIsVisible)
            {
                return new Data.XHitResult(false, null, default(Point));
            }

            Type type = typeof(T);
            Point pos = this.XGetAbsolutePos();
            Size size = this.XGetSize();

            if (pointInScene.X >= pos.X
                && pointInScene.Y >= pos.Y
                && pointInScene.X <= pos.X + size.Width
                && pointInScene.Y <= pos.Y + size.Height)
            {
                for (int index = this._partCollection.Count - 1; index >= 0; index--)
                {
                    Data.XHitResult hitResult = this._partCollection[index].XHitTest<T>(pointInScene);
                    if (hitResult.IsSuccess)
                    {
                        return hitResult;
                    }
                }
                if (this.GetType() == type || this.GetType().IsSubclassOf(type)
                    || type.IsAssignableFrom(this.GetType()))
                {
                    return new Data.XHitResult(true, this, new Point(pointInScene.X - pos.X, pointInScene.Y - pos.Y));
                }
            }
            return new Data.XHitResult(false, null, default(Point));
        }

        #region PartContainer

        public List<Part> GetPartList()
        {
            return _partCollection.PartList;
        }

        /// <summary>
        /// 添加子组件
        /// </summary>
        /// <param name="part"></param>
        public void AddPart(Part part)
        {
            if (ValidateChildType(part.GetType()))
            {
                if (part is AreaPart)
                {
                    this._subAreas.Add((AreaPart)part);
                }
                _partCollection.Add(part);

                _canvas.Children.Add(part);
                Canvas.SetZIndex(part, _canvas.Children.Count - 1);

                Canvas.SetLeft(part, part.XLeft);
                Canvas.SetTop(part, part.XTop);

                part.ParentPart = this;
            }
        }

        public void XRemovePart(Part part)
        {
            if (part is AreaPart)
            {
                this._subAreas.Remove((AreaPart)part);
            }
            _partCollection.Remove(part);

            _canvas.Children.Remove(part);
        }

        public Part GetChildPart(string partName, bool isRecursive)
        {
            return _partCollection.GetChildPart(partName, isRecursive);
        }

        /// <summary>
        /// 根据类型来获取组件里包含的子组件
        /// </summary>
        /// <param name="isRecursive"></param>
        /// <returns></returns>
        public List<T> GetChildPartByType<T>(bool isRecursive)
        {
            return _partCollection.GetChildPartByType<T>(isRecursive);
        }

        public bool ValidateChildType(Type childType)
        {
            if (childType == typeof(AreaPart) || childType.IsSubclassOf(typeof(AreaPart)))
            {
                return true;
            }
            else if (childType == typeof(PartFrame) || childType.IsSubclassOf(typeof(PartFrame)))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取实际的可存放组件的容器控件
        /// </summary>
        /// <returns></returns>
        public UIElement GetContentContainer()
        {
            return this._canvas;
        }

        public void BringPartTo(Part part, int index)
        {
            XRemovePart(part);

            if (part is AreaPart)
            {
                this._subAreas.Add((AreaPart)part);
            }
            _partCollection.Insert(part, index);

            _canvas.Children.Insert(index, part);
            Canvas.SetZIndex(part, index);

            Canvas.SetLeft(part, part.XLeft);
            Canvas.SetTop(part, part.XTop);

            part.ParentPart = this;
        }

        public int GetPartIndex(Part part)
        {
            if (part != null)
            {
                if (_partCollection != null && _partCollection.Count > 0)
                {
                    for (int index = 0; index < _partCollection.Count; index++)
                    {
                        if (_partCollection[index] == part)
                        {
                            return index;
                        }
                    }
                }
            }
            return -1;
        }

        public int GetSendToBackIndex(Part part)
        {
            return 0;
        }

        public int GetBringToFrontIndex(Part part)
        {
            return _partCollection.Count - 1;
        }
        public int GetForwardIndex(Part part)
        {
            int index = GetPartIndex(part);
            return index < _partCollection.Count - 1 ? index + 1 : index;
        }

        public int GetBackwardIndex(Part part)
        {
            int index = GetPartIndex(part);
            return index > 0 ? index - 1 : index;
        }

        public Tuple<Point?, Point?, byte> GetAlignLinePoint(Part part, double left = -1, double top = -1, double right = -1, double bottom = -1)
        {
            //00表示left和top，01表示right和top，10表示left和bottom，11表示right和bottom
            byte bDirection = 0;
            Point? leftOrRight = null;
            Point? topOrBottom = null;
            double minOffsetX = double.MaxValue;
            double minOffsetY = double.MaxValue;
            for (int index = 0; index < _partCollection.Count; index++)
            {
                Part destPart = _partCollection[index];
                if (destPart != part)
                {
                    if (left >= 0)
                    {
                        if (Math.Abs(destPart.XLeft - left) < 2 && Math.Abs(destPart.XLeft - left) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.XLeft - left);
                            leftOrRight = new Point(destPart.XLeft, destPart.XTop + destPart.XHeight / 2);
                            bDirection &= 2;
                        }
                        else if (Math.Abs(destPart.XLeft + destPart.XWidth - left) < 2 && Math.Abs(destPart.XLeft + destPart.XWidth - left) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.XLeft + destPart.XWidth - left);
                            leftOrRight = new Point(destPart.XLeft + destPart.XWidth, destPart.XTop + destPart.XHeight / 2);
                            bDirection &= 2;
                        }
                    }
                    if (top >= 0)
                    {
                        if (Math.Abs(destPart.XTop - top) < 2 && Math.Abs(destPart.XTop - top) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.XTop - top);
                            topOrBottom = new Point(destPart.XLeft + destPart.XWidth / 2, destPart.XTop);
                            bDirection &= 1;
                        }
                        else if (Math.Abs(destPart.XTop + destPart.XHeight - top) < 2 && Math.Abs(destPart.XTop + destPart.XHeight - top) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.XTop + destPart.XHeight - top);
                            topOrBottom = new Point(destPart.XLeft + destPart.XWidth / 2, destPart.XTop + destPart.XHeight);
                            bDirection &= 1;
                        }
                    }
                    if (right >= 0)
                    {
                        if (Math.Abs(destPart.XLeft - right) < 2 && Math.Abs(destPart.XLeft - right) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.XLeft - right);
                            leftOrRight = new Point(destPart.XLeft, destPart.XTop + destPart.XHeight / 2);
                            bDirection |= 1;
                        }
                        else if (Math.Abs(destPart.XLeft + destPart.XWidth - right) < 2 && Math.Abs(destPart.XLeft + destPart.XWidth - right) < minOffsetX)
                        {
                            minOffsetX = Math.Abs(destPart.XLeft + destPart.XWidth - right);
                            leftOrRight = new Point(destPart.XLeft + destPart.XWidth, destPart.XTop + destPart.XHeight / 2);
                            bDirection |= 1;
                        }
                    }
                    if (bottom >= 0)
                    {
                        if (Math.Abs(destPart.XTop - bottom) < 2 && Math.Abs(destPart.XTop - bottom) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.XTop - bottom);
                            topOrBottom = new Point(destPart.XLeft + destPart.XWidth / 2, destPart.XTop);
                            bDirection |= 2;
                        }
                        else if (Math.Abs(destPart.XTop + destPart.XHeight - bottom) < 2 && Math.Abs(destPart.XTop + destPart.XHeight - bottom) < minOffsetY)
                        {
                            minOffsetY = Math.Abs(destPart.XTop + destPart.XHeight - bottom);
                            topOrBottom = new Point(destPart.XLeft + destPart.XWidth / 2, destPart.XTop + destPart.XHeight);
                            bDirection |= 2;
                        }
                    }
                }
            }
            return new Tuple<Point?, Point?, byte>(leftOrRight, topOrBottom, bDirection);
        }
        #endregion

        public void RaiseScriptNetEvent(string eventName, string dataString)
        {
            for (int index = 0; index < _subAreas.Count; index++)
            {
                _subAreas[index].RaiseScriptNetEvent(eventName, dataString);
            }
        }
    }
}
